import pandas as pd
import os
import time
import requests
import json
from pathlib import Path
import random
import re
import base64
import uuid
from src.processors.image_editor import process_image_edit
from src.processors.i2v_processor import process_single_image_with_audio
from src.processors.oss_uploader import upload_file_and_get_url
import dashscope
from PIL import Image, ImageDraw, ImageFont
import copy
from collections import defaultdict


# 多套海报布局参数配置
POSTER_LAYOUT_CONFIGS = [
    {
        "name": "布局1",
        "base_sizes": {
            "title_ratio": 0.08,
            "time_ratio": 0.015,
            "copywriting_ratio": 0.05,
            "team_name_ratio": 0.03,
            "vs_ratio": 0.035,
            "vietnam_title_ratio": 0.1,
            "first_part_ratio": 0.05,
            "second_part_ratio": 0.035,
            "vs_text_ratio": 0.06,
            "match_time_ratio": 0.03,
            "default_text_ratio": 0.025,
            "logo_size_ratio": 0.12,
            "telegram_ratio": 0.025,
            "telegram_text_spacing": 10,
            "bottom_elements_y_offset": 20
        },
        "positions": {
            "vietnam_text_y_ratio": 0.1,
            "first_part_y_offset": -200,
            "second_part_y_base": 9/16,
            "second_part_y_offset": -200,
            "second_part_y_final_offset": 200,
            "logo_y_base": 6/16,
            "logo_y_offset": 200,
            "logo_y_final_offset": -200,
            "team_name_y_multiplier": 1.2,
            "vs_text_y_multiplier": 0.5,
            "match_time_y_base": 13/16,
            "telegram_y_offset": 20
        },
        "text_effects": {
            "vietnam_text_bold_range": (-3, 4),
            "first_part_bold_range": (-3, 4),
            "second_part_bold_range": (-1, 2),
            "team_name_bold_range": (-1, 2),
            "vs_text_bold_range": (-3, 4),
            "match_time_bold_range": (-1, 2),
            "telegram_text_bold_range": (-1, 2)
        },
        "line_break": {
            "max_chars_per_line": 18
        }
    }
]


def read_excel_data(excel_path):
    """
    读取Excel文件中的比赛信息
    
    Args:
        excel_path (str): Excel文件路径
        
    Returns:
        list: 包含比赛信息的字典列表
    """
    try:
        # 读取Excel文件
        df = pd.read_excel(excel_path)
        
        print(f"从Excel文件 {excel_path} 中读取到 {len(df)} 行数据")
        # 打印列名用于调试
        print("Excel列名:", df.columns.tolist())
        
        # 检查是否包含所需的列
        required_columns = ['比赛时间', '球队A', '球队A队标链接', '球队B', '球队B队标链接', '文案']
        missing_columns = [col for col in required_columns if col not in df.columns]
        if missing_columns:
            raise Exception(f"Excel文件缺少必要的列: {missing_columns}")
        
        # 提取所需列信息
        matches_data = []
        for index, row in df.iterrows():
            # 跳过完全空的行（通常是表头后的空行）
            if pd.isna(row['比赛时间']) and pd.isna(row['球队A']) and pd.isna(row['球队B']):
                print(f"跳过空行: 第 {index+1} 行")
                continue
                
            # 处理可能的NaN值并去除首尾空格
            match_time = row['比赛时间']
            team_a = row['球队A']
            team_a_logo = row['球队A队标链接']
            team_b = row['球队B']
            team_b_logo = row['球队B队标链接']
            copywriting = row['文案']
            match_id = row.get('match_id', '')  # 获取match_id，如果没有则为空字符串
            
            # 处理NaN值并去除首尾空格
            match_time = '' if pd.isna(match_time) else str(match_time).strip()
            team_a = '' if pd.isna(team_a) else str(team_a).strip()
            team_a_logo = '' if pd.isna(team_a_logo) else str(team_a_logo).strip()
            team_b = '' if pd.isna(team_b) else str(team_b).strip()
            team_b_logo = '' if pd.isna(team_b_logo) else str(team_b_logo).strip()
            copywriting = '' if pd.isna(copywriting) else str(copywriting).strip()
            match_id = '' if pd.isna(match_id) else str(match_id).strip()
            
            # 跳过关键字段都为空的行
            if not match_time and not team_a and not team_b:
                print(f"跳过关键字段为空的行: 第 {index+1} 行")
                continue
            
            match_info = {
                'match_time': match_time,          # 日期+时间
                'team_a': team_a,                  # 主队名称
                'team_a_logo': team_a_logo,        # 主队队标链接
                'team_b': team_b,                  # 客队名称
                'team_b_logo': team_b_logo,        # 客队队标链接
                'copywriting': copywriting,        # 文案
                'match_id': match_id               # 分组ID
            }
            matches_data.append(match_info)
            print(f"读取到第 {index+1} 行比赛数据: 时间='{match_time}', 球队A='{team_a}', 球队B='{team_b}', 分组ID='{match_id}'")  # 调试信息
        
        print(f"总共读取到 {len(matches_data)} 条比赛数据")
        return matches_data
    except Exception as e:
        raise Exception(f"读取Excel文件失败: {str(e)}")


def group_matches_by_id(matches_data):
    """
    根据match_id对比赛进行分组
    
    Args:
        matches_data (list): 比赛数据列表
        
    Returns:
        dict: 以match_id为键，比赛列表为值的字典
    """
    grouped_matches = defaultdict(list)
    
    for match in matches_data:
        match_id = match.get('match_id', '')
        if not match_id:
            # 如果没有match_id，则每场比赛单独作为一个组
            match_id = str(uuid.uuid4())  # 生成唯一ID
        grouped_matches[match_id].append(match)
    
    return dict(grouped_matches)


def sanitize_filename(filename):
    """
    清理文件名中的非法字符
    
    Args:
        filename (str): 原始文件名
        
    Returns:
        str: 清理后的文件名
    """
    # 替换Windows非法字符
    illegal_chars = '<>:"/\\|?*'
    for char in illegal_chars:
        filename = filename.replace(char, '_')
    
    # 替换其他可能导致问题的字符
    filename = filename.replace('\n', ' ').replace('\r', ' ')
    
    # 限制文件名长度
    if len(filename) > 150:
        filename = filename[:150]
    
    # 去除首尾空格
    filename = filename.strip()
    
    return filename


def base64_to_image_file(base64_string, output_dir, prefix="team_logo"):
    """
    将base64字符串转换为图片文件并保存
    
    Args:
        base64_string (str): base64编码的图片数据
        output_dir (str): 输出目录
        prefix (str): 文件名前缀
        
    Returns:
        str: 保存的文件路径
    """
    try:
        # 检查是否是有效的base64字符串
        if not base64_string or not base64_string.startswith('data:image'):
            return None
            
        # 解析base64数据
        header, encoded_data = base64_string.split(',', 1)
        file_extension = header.split('/')[1].split(';')[0]
        
        # 解码base64数据
        image_data = base64.b64decode(encoded_data)
        
        # 生成文件名
        filename = f"{prefix}_{random.randint(1000, 9999)}.{file_extension}"
        file_path = os.path.join(output_dir, filename)
        
        # 保存图片文件
        with open(file_path, 'wb') as f:
            f.write(image_data)
            
        return file_path
    except Exception as e:
        print(f"Base64转换为图片文件失败: {e}")
        return None


def add_text_and_logos_to_image(image_path, output_path, match_info):
    """
    在图片上添加文本和队伍图标
    
    Args:
        image_path (str): 原始图片路径
        output_path (str): 输出图片路径
        match_info (dict): 比赛信息
        
    Returns:
        bool: 是否成功
    """
    try:
        # 随机选择一个布局配置
        POSTER_LAYOUT_CONFIG = copy.deepcopy(random.choice(POSTER_LAYOUT_CONFIGS))
        print(f"使用布局配置: {POSTER_LAYOUT_CONFIG['name']}")
        
        # 打开背景图片
        bg_image = Image.open(image_path).convert("RGBA")
        width, height = bg_image.size
        
        # 创建一个可以在上面绘制的对象
        draw = ImageDraw.Draw(bg_image)
        
        # 根据图片分辨率调整字体大小
        # 基准字体大小，根据图片高度调整
        base_title_size = int(height * POSTER_LAYOUT_CONFIG["base_sizes"]["title_ratio"])
        base_time_size = int(height * POSTER_LAYOUT_CONFIG["base_sizes"]["time_ratio"])
        base_copywriting_size = int(height * POSTER_LAYOUT_CONFIG["base_sizes"]["copywriting_ratio"])
        base_team_name_size = int(height * POSTER_LAYOUT_CONFIG["base_sizes"]["team_name_ratio"])
        base_vs_size = int(height * POSTER_LAYOUT_CONFIG["base_sizes"]["vs_ratio"])
        
        # 尝试加载中文字体，如果失败则使用默认字体
        try:
            # 使用项目fonts目录下的字体文件，随机选择一个字体
            from src.utils.font_utils import get_random_font
            
            # 创建字体
            font_large = get_random_font(base_title_size)
            font_medium = get_random_font(base_time_size)
            font_small = get_random_font(base_copywriting_size)
            font_team = get_random_font(base_team_name_size)
            font_vs = get_random_font(base_vs_size)
        except Exception as e:
            print(f"加载字体文件失败: {e}，使用默认字体")
            # 使用默认字体
            font_large = ImageFont.load_default()
            font_medium = ImageFont.load_default()
            font_small = ImageFont.load_default()
            font_team = ImageFont.load_default()
            font_vs = ImageFont.load_default()
        
        # 添加"足球"越南语文本（放在图片最上方，水平居中，加粗加大）
        vietnam_text = "Bóng đá"  # 足球的越南语
        try:
            font_for_vietnam = get_random_font(int(height * POSTER_LAYOUT_CONFIG["base_sizes"]["vietnam_title_ratio"]))
        except:
            font_for_vietnam = ImageFont.load_default()
        
        left, top, right, bottom = draw.textbbox((0, 0), vietnam_text, font=font_for_vietnam)
        text_width = right - left
        x = (width - text_width) // 2
        y = int(height * POSTER_LAYOUT_CONFIG["positions"]["vietnam_text_y_ratio"])
        
        # 加粗效果（使用更密集的网格）
        bold_range = POSTER_LAYOUT_CONFIG["text_effects"]["vietnam_text_bold_range"]
        for dx in range(bold_range[0], bold_range[1]):
            for dy in range(bold_range[0], bold_range[1]):
                draw.text((x+dx, y+dy), vietnam_text, font=font_for_vietnam, fill=(0, 0, 0, 255))
        draw.text((x, y), vietnam_text, font=font_for_vietnam, fill=(255, 255, 255, 255))
        
        # 添加文案的第一部分（放在图片较上方，加粗）
        copywriting = match_info['copywriting']
        lines = []
        if '\n' in copywriting:
            lines = copywriting.split('\n')
        else:
            lines = [copywriting]
        
        if len(lines) > 0:
            first_part = lines[0]
            try:
                font_for_first_part = get_random_font(int(height * POSTER_LAYOUT_CONFIG["base_sizes"]["first_part_ratio"]))
            except:
                font_for_first_part = ImageFont.load_default()
            
            left, top, right, bottom = draw.textbbox((0, 0), first_part, font=font_for_first_part)
            text_width = right - left
            x = (width - text_width) // 2
            y = int(height * 3 // 8) + POSTER_LAYOUT_CONFIG["positions"]["first_part_y_offset"]
            
            # 进一步增强加粗效果（使用更密集的网格）
            bold_range = POSTER_LAYOUT_CONFIG["text_effects"]["first_part_bold_range"]
            for dx in range(bold_range[0], bold_range[1]):
                for dy in range(bold_range[0], bold_range[1]):
                    draw.text((x+dx, y+dy), first_part, font=font_for_first_part, fill=(0, 0, 0, 255))
            draw.text((x, y), first_part, font=font_for_first_part, fill=(255, 255, 255, 255))
        
        # 添加文案的第二部分（放在图片中部，支持换行）
        if len(lines) > 1:
            second_part = lines[1]
            # 检查是否需要换行
            try:
                font_for_second_part = get_random_font(int(height * POSTER_LAYOUT_CONFIG["base_sizes"]["second_part_ratio"]))
            except:
                font_for_second_part = ImageFont.load_default()
            
            # 如果文本太长，进行换行处理
            second_lines = []
            max_chars_per_line = POSTER_LAYOUT_CONFIG["line_break"]["max_chars_per_line"]
            if len(second_part) > max_chars_per_line:
                # 更智能的换行处理
                words = second_part.split(' ')
                current_line = ""
                for word in words:
                    if len(current_line + word) <= max_chars_per_line:
                        current_line += word + " "
                    else:
                        if current_line:
                            second_lines.append(current_line.strip())
                        current_line = word + " "
                
                if current_line:
                    second_lines.append(current_line.strip())
                
                # 如果没有找到合适的断点，则强制在指定位置断行
                if not second_lines:
                    split_pos = max_chars_per_line
                    second_lines = [second_part[:split_pos].strip(), second_part[split_pos:].strip()]
            else:
                second_lines = [second_part]
            
            # 根据行数和文本长度动态调整字体大小，使字体看起来更厚重
            max_line_length = max(len(line) for line in second_lines)
            if max_line_length <= 10:
                try:
                    font_for_second_part = get_random_font(int(height * 0.05))
                except:
                    font_for_second_part = ImageFont.load_default()
            elif max_line_length <= 20:
                try:
                    font_for_second_part = get_random_font(int(height * 0.045))
                except:
                    font_for_second_part = ImageFont.load_default()
            elif max_line_length <= 30:
                try:
                    font_for_second_part = get_random_font(int(height * 0.04))
                except:
                    font_for_second_part = ImageFont.load_default()
            else:
                try:
                    font_for_second_part = get_random_font(int(height * POSTER_LAYOUT_CONFIG["base_sizes"]["second_part_ratio"]))
                except:
                    font_for_second_part = ImageFont.load_default()
            
            # 计算每行文本的位置
            total_height = 0
            line_heights = []
            line_widths = []
            
            for line in second_lines:
                left, top, right, bottom = draw.textbbox((0, 0), line, font=font_for_second_part)
                line_width = right - left
                line_height = bottom - top
                line_widths.append(line_width)
                line_heights.append(line_height)
                total_height += line_height
            
            # 根据行数确定起始Y位置（放在图片下部）
            if len(second_lines) == 1:
                start_y = int(height * POSTER_LAYOUT_CONFIG["positions"]["second_part_y_base"]) + POSTER_LAYOUT_CONFIG["positions"]["second_part_y_offset"] + POSTER_LAYOUT_CONFIG["positions"]["second_part_y_final_offset"]
            else:
                start_y = int(height * POSTER_LAYOUT_CONFIG["positions"]["second_part_y_base"]) + POSTER_LAYOUT_CONFIG["positions"]["second_part_y_offset"] + POSTER_LAYOUT_CONFIG["positions"]["second_part_y_final_offset"]
            
            # 绘制每一行文本，通过多重绘制实现加粗效果
            bold_range = POSTER_LAYOUT_CONFIG["text_effects"]["second_part_bold_range"]
            for i, (line, line_width, line_height) in enumerate(zip(second_lines, line_widths, line_heights)):
                x = (width - line_width) // 2
                y = start_y + i * int(line_height * 1.3)  # 行间距为字体高度的1.3倍
                
                # 通过多次绘制同一文本实现加粗效果
                for dx in range(bold_range[0], bold_range[1]):
                    for dy in range(bold_range[0], bold_range[1]):
                        draw.text((x+dx, y+dy), line, font=font_for_second_part, fill=(0, 0, 0, 255))
                draw.text((x, y), line, font=font_for_second_part, fill=(255, 255, 255, 255))
        
        # 根据图片高度调整图标大小
        logo_size = int(height * POSTER_LAYOUT_CONFIG["base_sizes"]["logo_size_ratio"])
        
        # 计算图标位置（整体位置往上抬）
        logo_a_x = width // 4 - logo_size // 2
        logo_b_x = width * 3 // 4 - logo_size // 2
        logo_y = int(height * POSTER_LAYOUT_CONFIG["positions"]["logo_y_base"]) + POSTER_LAYOUT_CONFIG["positions"]["logo_y_offset"] + POSTER_LAYOUT_CONFIG["positions"]["logo_y_final_offset"]
        
        # 在图标下方添加球队名称
        team_a_name = match_info['team_a']
        team_b_name = match_info['team_b']
        
        # 计算球队A名称位置（放在图标下方）
        left, top, right, bottom = draw.textbbox((0, 0), team_a_name, font=font_team)
        text_width = right - left
        x = logo_a_x + (logo_size - text_width) // 2
        y = logo_y + int(logo_size * POSTER_LAYOUT_CONFIG["positions"]["team_name_y_multiplier"])
        
        # 添加艺术字效果（红色描边）并加粗
        bold_range = POSTER_LAYOUT_CONFIG["text_effects"]["team_name_bold_range"]
        for dx in range(bold_range[0], bold_range[1]):
            for dy in range(bold_range[0], bold_range[1]):
                draw.text((x+dx, y+dy), team_a_name, font=font_team, fill=(255, 0, 0, 255))
        draw.text((x, y), team_a_name, font=font_team, fill=(255, 255, 255, 255))
        
        # 计算球队B名称位置（放在图标下方）
        left, top, right, bottom = draw.textbbox((0, 0), team_b_name, font=font_team)
        text_width = right - left
        x = logo_b_x + (logo_size - text_width) // 2
        y = logo_y + int(logo_size * POSTER_LAYOUT_CONFIG["positions"]["team_name_y_multiplier"])
        
        # 添加艺术字效果（蓝色描边）并加粗
        bold_range = POSTER_LAYOUT_CONFIG["text_effects"]["team_name_bold_range"]
        for dx in range(bold_range[0], bold_range[1]):
            for dy in range(bold_range[0], bold_range[1]):
                draw.text((x+dx, y+dy), team_b_name, font=font_team, fill=(0, 0, 255, 255))
        draw.text((x, y), team_b_name, font=font_team, fill=(255, 255, 255, 255))
        
        # 添加VS文本（放在两队标之间，水平居中）
        vs_text = "VS"
        try:
            font_vs = get_random_font(int(height * POSTER_LAYOUT_CONFIG["base_sizes"]["vs_text_ratio"]))
        except:
            font_vs = ImageFont.load_default()
        
        left, top, right, bottom = draw.textbbox((0, 0), vs_text, font=font_vs)
        text_width = right - left
        text_height = bottom - top
        x = (width - text_width) // 2
        y = logo_y + int(logo_size * POSTER_LAYOUT_CONFIG["positions"]["vs_text_y_multiplier"])
        
        # 加粗效果（使用更密集的网格）
        bold_range = POSTER_LAYOUT_CONFIG["text_effects"]["vs_text_bold_range"]
        for dx in range(bold_range[0], bold_range[1]):
            for dy in range(bold_range[0], bold_range[1]):
                draw.text((x+dx, y+dy), vs_text, font=font_vs, fill=(0, 0, 0, 255))
        draw.text((x, y), vs_text, font=font_vs, fill=(255, 215, 0, 255))  # 金色
        
        # 添加比赛时间（放在图片底部附近，移除椭圆背景）
        time_text = match_info['match_time']
        try:
            font_time = get_random_font(int(height * POSTER_LAYOUT_CONFIG["base_sizes"]["match_time_ratio"]))
        except:
            font_time = ImageFont.load_default()
        
        left, top, right, bottom = draw.textbbox((0, 0), time_text, font=font_time)
        text_width = right - left
        x = (width - text_width) // 2
        y = int(height * POSTER_LAYOUT_CONFIG["positions"]["match_time_y_base"])
        
        # 加粗时间文本
        bold_range = POSTER_LAYOUT_CONFIG["text_effects"]["match_time_bold_range"]
        for dx in range(bold_range[0], bold_range[1]):
            for dy in range(bold_range[0], bold_range[1]):
                draw.text((x+dx, y+dy), time_text, font=font_time, fill=(0, 0, 0, 255))
        draw.text((x, y), time_text, font=font_time, fill=(255, 255, 0, 255))  # 黄色
        
        # 添加默认图片"telegram.png"在图片底部
        telegram_img = Image.open("static/images/telegram.png")
        # 调整图片大小，使用高度的2.5%以使图片更小
        new_height = int(height * POSTER_LAYOUT_CONFIG["base_sizes"]["telegram_ratio"])
        aspect_ratio = telegram_img.width / telegram_img.height
        new_width = int(new_height * aspect_ratio)
        telegram_img = telegram_img.resize((new_width, new_width))
        
        # 在telegram图片右侧添加"LUCKYFF8"文本
        default_text = "LUCKYFF8"
        try:
            font_default = get_random_font(int(height * POSTER_LAYOUT_CONFIG["base_sizes"]["default_text_ratio"]))
        except:
            font_default = ImageFont.load_default()
        
        left, top, right, bottom = draw.textbbox((0, 0), default_text, font=font_default)
        text_width = right - left
        text_height = bottom - top
        
        # 计算整体宽度（图片宽度 + 间距 + 文本宽度）
        spacing = POSTER_LAYOUT_CONFIG["base_sizes"]["telegram_text_spacing"]
        total_width = new_width + spacing + text_width
        
        # 计算整体位置 (距离底部20像素，水平居中)
        total_x = (width - total_width) // 2
        total_y = height - max(new_height, text_height) - POSTER_LAYOUT_CONFIG["positions"]["telegram_y_offset"]
        
        # 放置telegram图片
        img_x = total_x
        img_y = total_y + (max(new_height, text_height) - new_height) // 2  # 垂直居中对齐
        bg_image.paste(telegram_img, (img_x, img_y), telegram_img if telegram_img.mode == 'RGBA' else None)
        
        # 放置"LUCKYFF8"文本
        text_x = total_x + new_width + spacing
        text_y = total_y + (max(new_height, text_height) - text_height) // 2 - 9  # 垂直居中对齐
        
        # 添加文本阴影效果
        bold_range = POSTER_LAYOUT_CONFIG["text_effects"]["telegram_text_bold_range"]
        for dx in range(bold_range[0], bold_range[1]):
            for dy in range(bold_range[0], bold_range[1]):
                draw.text((text_x+dx, text_y+dy), default_text, font=font_default, fill=(0, 0, 0, 255))
        draw.text((text_x, text_y), default_text, font=font_default, fill=(255, 255, 255, 255))
        # 处理队伍图标，调整图标尺寸和位置
        team_a_logo_path = base64_to_temp_image(match_info['team_a_logo'], "team_a_logo")
        team_b_logo_path = base64_to_temp_image(match_info['team_b_logo'], "team_b_logo")
        
        if team_a_logo_path:
            try:
                team_a_logo = Image.open(team_a_logo_path).convert("RGBA")
                team_a_logo = team_a_logo.resize((logo_size, logo_size))
                
                # 放置在左下方
                bg_image.paste(team_a_logo, (logo_a_x, logo_y), team_a_logo)
            except Exception as e:
                print(f"处理队伍A图标时出错: {e}")
        
        if team_b_logo_path:
            try:
                team_b_logo = Image.open(team_b_logo_path).convert("RGBA")
                team_b_logo = team_b_logo.resize((logo_size, logo_size))
                
                # 放置在右下方
                bg_image.paste(team_b_logo, (logo_b_x, logo_y), team_b_logo)
            except Exception as e:
                print(f"处理队伍B图标时出错: {e}")
        
        # 保存最终图片
        bg_image.convert("RGB").save(output_path)
        print(f"已保存带文本和图标的图片: {output_path}")
        
        # 清理临时文件
        if 'team_a_logo_path' in locals() and team_a_logo_path and os.path.exists(team_a_logo_path):
            os.remove(team_a_logo_path)
        if 'team_b_logo_path' in locals() and team_b_logo_path and os.path.exists(team_b_logo_path):
            os.remove(team_b_logo_path)
            
        return True
    except Exception as e:
        print(f"在图片上添加文本和图标时出错: {e}")
        return False


def base64_to_temp_image(base64_string, prefix="team_logo"):
    """
    将base64字符串转换为临时图片文件并保存
    
    Args:
        base64_string (str): base64编码的图片数据
        prefix (str): 文件名前缀
        
    Returns:
        str: 保存的文件路径，如果失败则返回None
    """
    try:
        # 检查是否是有效的base64字符串
        if not base64_string or not base64_string.startswith('data:image'):
            return None
            
        # 解析base64数据
        header, encoded_data = base64_string.split(',', 1)
        file_extension = header.split('/')[1].split(';')[0]
        
        # 解码base64数据
        image_data = base64.b64decode(encoded_data)
        
        # 生成临时文件名
        filename = f"{prefix}_{random.randint(1000, 9999)}.{file_extension}"
        temp_dir = os.path.join(os.getcwd(), 'temp')
        os.makedirs(temp_dir, exist_ok=True)
        file_path = os.path.join(temp_dir, filename)
        
        # 保存图片文件
        with open(file_path, 'wb') as f:
            f.write(image_data)
            
        return file_path
    except Exception as e:
        print(f"Base64转换为图片文件失败: {e}")
        return None


def generate_background_poster(api_key, prompt_text, wh_ratios="竖版", output_path=None):
    """
    使用AI生成没有文本和图标的背景海报
    
    Args:
        api_key (str): DashScope API密钥
        prompt_text (str): 提示词（仅包含背景描述）
        wh_ratios (str): 宽高比，"竖版"或"横版"
        output_path (str): 输出图片路径
        
    Returns:
        tuple: (成功状态, 结果信息或错误信息)
    """
    try:
        # 设置API基础URL
        dashscope.base_http_api_url = 'https://dashscope.aliyuncs.com/api/v1'
        
        # 根据宽高比设置图片尺寸
        if wh_ratios == "横版":
            size = "1664*928"  # 横版使用1664*928
        else:
            size = "928*1664"  # 竖版使用928*1664
        
        # 构造请求数据
        data = {
            "model": "qwen-image-plus",
            "input": {
                "prompt": prompt_text
            },
            "parameters": {
                "size": size,
                "n": 1,
                "prompt_extend": True,
                "watermark": False
            }
        }
        
        # 设置请求头
        headers = {
            'X-DashScope-Async': 'enable',
            'Content-Type': 'application/json',
            'Authorization': f'Bearer {api_key}'
        }
        
        print(f"正在提交海报生成任务...")
        print(f"提示词: {prompt_text}")
        print(f"尺寸: {size}")
        
        # 提交海报生成任务
        response = requests.post(
            'https://dashscope.aliyuncs.com/api/v1/services/aigc/text2image/image-synthesis',
            headers=headers,
            json=data
        )
        
        if response.status_code != 200:
            error_msg = f"海报生成任务提交失败，状态码: {response.status_code}，响应: {response.text}"
            print(error_msg)
            return False, error_msg
        
        response_data = response.json()
        print(f"海报生成API响应: {response_data}")
        
        # 检查响应中是否包含任务ID
        if 'output' not in response_data or 'task_id' not in response_data['output']:
            error_msg = f"海报生成任务提交成功，但响应中未包含task_id字段。完整响应: {response_data}"
            print(error_msg)
            return False, error_msg
        
        task_id = response_data['output']['task_id']
        print(f"海报生成任务已提交，任务ID: {task_id}")
        
        # 等待任务完成
        image_url = None
        task_status = None
        max_attempts = 60  # 最多等待10分钟(60次*10秒)
        attempt = 0
        
        while attempt < max_attempts:
            print(f"正在等待海报生成完成... (尝试 {attempt+1}/{max_attempts})")
            time.sleep(10)  # 等待10秒后查询状态
            
            # 查询任务状态
            status_response = requests.get(
                f'https://dashscope.aliyuncs.com/api/v1/tasks/{task_id}',
                headers={'Authorization': f'Bearer {api_key}'}
            )
            
            print(f"任务状态查询响应状态码: {status_response.status_code}")
            
            if status_response.status_code == 200:
                status_data = status_response.json()
                print(f"任务状态查询完整响应: {status_data}")
                
                if 'output' not in status_data or 'task_status' not in status_data['output']:
                    error_msg = f"任务状态查询成功，但响应中未包含task_status字段。完整响应: {status_data}"
                    print(error_msg)
                    return False, error_msg
                
                task_status = status_data['output']['task_status']
                print(f"任务状态: {task_status}")
                
                # 检查任务是否失败
                if task_status == 'FAILED':
                    error_message = status_data.get('output', {}).get('message', '未知错误')
                    error_code = status_data.get('output', {}).get('code', '未知错误码')
                    error_msg = f"海报生成失败: 错误码 {error_code}, 错误信息: {error_message}"
                    print(error_msg)
                    return False, error_msg
                elif task_status == 'SUCCEEDED':
                    if 'results' not in status_data['output'] or not status_data['output']['results']:
                        error_msg = f"任务执行成功，但响应中未包含results字段或结果为空。完整响应: {status_data}"
                        print(error_msg)
                        return False, error_msg
                    
                    # 获取生成的图片URL
                    image_url = status_data['output']['results'][0]['url']
                    print(f"海报生成完成，URL: {image_url}")
                    break
                elif task_status == 'CANCELED':
                    error_msg = "海报生成任务已取消"
                    print(error_msg)
                    return False, error_msg
            else:
                error_msg = f"查询任务状态失败，状态码: {status_response.status_code}，响应内容: {status_response.text}"
                print(error_msg)
            
            attempt += 1
        
        if not image_url:
            error_msg = f"海报生成超时，最终任务状态: {task_status}"
            print(error_msg)
            return False, error_msg
        
        # 如果提供了输出路径，则下载图片
        if output_path:
            print("正在下载海报图片...")
            image_data = requests.get(image_url)
            if image_data.status_code == 200:
                with open(output_path, 'wb') as f:
                    f.write(image_data.content)
                print(f"海报图片已保存到: {output_path}")
                return True, output_path
            else:
                error_msg = f"下载海报图片失败，状态码: {image_data.status_code}"
                print(error_msg)
                return False, error_msg
        else:
            # 如果没有提供输出路径，直接返回URL
            return True, image_url
            
    except Exception as e:
        error_msg = f"海报生成过程中出错: {str(e)}"
        print(error_msg)
        return False, error_msg


def generate_complete_poster(api_key, match_data, wh_ratios="竖版", output_path=None):
    """
    使用AI直接生成完整的海报图片（包含所有文本和图标）
    
    Args:
        api_key (str): DashScope API密钥
        match_data (list): 比赛数据列表
        wh_ratios (str): 宽高比，"竖版"或"横版"
        output_path (str): 输出图片路径
        
    Returns:
        tuple: (成功状态, 结果信息或错误信息)
    """
    try:
        # 设置API基础URL
        dashscope.base_http_api_url = 'https://dashscope.aliyuncs.com/api/v1'
        
        # 构造提示词
        prompt_text = """Create a football betting analysis poster. Background should be a green gradient with a stadium scene at the bottom, featuring bright lights and fog effects. At the top, write "futebol" in stylized cursive font followed by "ANÁLISE E PREVISÃO DE APOSTAS" in bold white.

List three matches with logos:
"""
        
        # 添加比赛信息
        for i, match in enumerate(match_data, 1):  # 限制最多3场比赛
            prompt_text += f"{i}. {match['team_a']} vs {match['team_b']} - {match['match_time']}\n"
        
        prompt_text += """
Each match must have official club logos and centered "VS" graphic in green/blue split design. Dates and times must remain unchanged.

At the bottom, add a dark stadium scene with illuminated stands and mist. Include a green-blue gradient button with "LUCKYFF8" and Instagram icon. Below it, write "Obtenha dados e análises das partidas." in sans-serif font.

Keep text exactly as specified but allow for variations in layout, colors, and visual effects."""
        
        # 根据宽高比设置图片尺寸
        if wh_ratios == "横版":
            size = "1664*928"  # 横版使用1664*928
        else:
            size = "928*1664"  # 竖版使用928*1664
        
        print(f"正在提交完整海报生成任务...")
        print(f"提示词: {prompt_text}")
        print(f"尺寸: {size}")
        
        # 使用正确的API调用方式
        rsp = dashscope.ImageSynthesis.call(
            api_key=api_key,
            model="wan2.5-t2i-preview",
            prompt=prompt_text,
            n=1,
            size=size,
            prompt_extend=False,
            watermark=False
        )
        
        # 检查响应状态
        if rsp.status_code != 200:
            error_msg = f"海报生成任务提交失败，状态码: {rsp.status_code}，响应: {rsp}"
            print(error_msg)
            return False, error_msg
        
        response_data = rsp
        print(f"海报生成API响应: {response_data}")
        
        # 检查响应中是否包含任务ID
        if 'output' not in response_data or 'task_id' not in response_data['output']:
            error_msg = f"海报生成任务提交成功，但响应中未包含task_id字段。完整响应: {response_data}"
            print(error_msg)
            return False, error_msg
        
        task_id = response_data['output']['task_id']
        print(f"海报生成任务已提交，任务ID: {task_id}")
        
        # 等待任务完成
        image_url = None
        task_status = None
        max_attempts = 60  # 最多等待10分钟(60次*10秒)
        attempt = 0
        
        while attempt < max_attempts:
            print(f"正在等待海报生成完成... (尝试 {attempt+1}/{max_attempts})")
            time.sleep(10)  # 等待10秒后查询状态
            
            # 查询任务状态
            status_response = requests.get(
                f'https://dashscope.aliyuncs.com/api/v1/tasks/{task_id}',
                headers={'Authorization': f'Bearer {api_key}'}
            )
            
            print(f"任务状态查询响应状态码: {status_response.status_code}")
            
            if status_response.status_code == 200:
                status_data = status_response.json()
                print(f"任务状态查询完整响应: {status_data}")
                
                if 'output' not in status_data or 'task_status' not in status_data['output']:
                    error_msg = f"任务状态查询成功，但响应中未包含task_status字段。完整响应: {status_data}"
                    print(error_msg)
                    return False, error_msg
                
                task_status = status_data['output']['task_status']
                print(f"任务状态: {task_status}")
                
                # 检查任务是否失败
                if task_status == 'FAILED':
                    error_message = status_data.get('output', {}).get('message', '未知错误')
                    error_code = status_data.get('output', {}).get('code', '未知错误码')
                    error_msg = f"海报生成失败: 错误码 {error_code}, 错误信息: {error_message}"
                    print(error_msg)
                    return False, error_msg
                elif task_status == 'SUCCEEDED':
                    if 'results' not in status_data['output'] or not status_data['output']['results']:
                        error_msg = f"任务执行成功，但响应中未包含results字段或结果为空。完整响应: {status_data}"
                        print(error_msg)
                        return False, error_msg
                    
                    # 获取生成的图片URL
                    image_url = status_data['output']['results'][0]['url']
                    print(f"海报生成完成，URL: {image_url}")
                    break
                elif task_status == 'CANCELED':
                    error_msg = "海报生成任务已取消"
                    print(error_msg)
                    return False, error_msg
            else:
                error_msg = f"查询任务状态失败，状态码: {status_response.status_code}，响应内容: {status_response.text}"
                print(error_msg)
            
            attempt += 1
        
        if not image_url:
            error_msg = f"海报生成超时，最终任务状态: {task_status}"
            print(error_msg)
            return False, error_msg
        
        # 如果提供了输出路径，则下载图片
        if output_path:
            print("正在下载海报图片...")
            image_data = requests.get(image_url)
            if image_data.status_code == 200:
                with open(output_path, 'wb') as f:
                    f.write(image_data.content)
                print(f"海报图片已保存到: {output_path}")
                return True, output_path
            else:
                error_msg = f"下载海报图片失败，状态码: {image_data.status_code}"
                print(error_msg)
                return False, error_msg
        else:
            # 如果没有提供输出路径，直接返回URL
            return True, image_url
            
    except Exception as e:
        error_msg = f"海报生成过程中出错: {str(e)}"
        print(error_msg)
        return False, error_msg


def process_match_images_new_method(excel_path, output_dir, api_key, language="zh"):
    """
    使用新方法处理Excel中的比赛信息，为每场比赛生成海报图片（避免文本错误）
    
    Args:
        excel_path (str): Excel文件路径
        output_dir (str): 输出目录
        api_key (str): DashScope API密钥
        language (str): 生成语言，'zh'表示中文，'vi'表示越南语
        
    Returns:
        list: 处理结果列表
    """
    print(f"开始处理图片（新方法）: Excel={excel_path}")
    
    # 读取Excel数据
    matches_data = read_excel_data(excel_path)
    if not matches_data:
        return []
    
    # 根据match_id对比赛进行分组
    grouped_matches = group_matches_by_id(matches_data)
    print(f"根据match_id分组完成，共{len(grouped_matches)}组")
    
    # 确保输出目录存在
    images_output_dir = os.path.join(output_dir, 'images')
    os.makedirs(images_output_dir, exist_ok=True)
    print(f"创建/确认图片输出目录: {images_output_dir}")
    
    results = []
    
    # 处理每个分组
    for match_id, batch_matches in grouped_matches.items():
        try:
            print(f"正在处理分组 {match_id}，包含 {len(batch_matches)} 场比赛")
            
            # 生成文件名
            first_match = batch_matches[0]
            safe_team_a = re.sub(r'[<>:"/\\|?*]', '_', first_match['team_a'])
            safe_team_b = re.sub(r'[<>:"/\\|?*]', '_', first_match['team_b'])
            
            # 根据语言添加语言标识
            lang_suffix = "_vi" if language == "vi" else ""
            filename = f"{safe_team_a}_vs_{safe_team_b}_complete{lang_suffix}_{uuid.uuid4().hex[:8]}.png"
            output_path = os.path.join(images_output_dir, filename)
            
            # 生成完整海报
            success, result = generate_complete_poster(
                api_key=api_key,
                match_data=batch_matches,
                wh_ratios="竖版",
                output_path=output_path
            )
            
            if not success:
                results.append({
                    'match_info': first_match,  # 使用第一场比赛作为代表
                    'image_path': None,
                    'status': 'failed',
                    'message': f"完整海报生成失败: {result}"
                })
                print(f"  完整海报生成失败: {result}")
                continue
            
            print(f"  完整海报生成成功: {output_path}")
            
            # 为批次中的每场比赛添加结果
            for match in batch_matches:
                results.append({
                    'match_info': match,
                    'image_path': output_path,
                    'status': 'success',
                    'message': '海报生成成功'
                })
            print(f"  海报生成成功")
                
        except Exception as e:
            # 为批次中的每场比赛添加错误结果
            for match in batch_matches:
                results.append({
                    'match_info': match,
                    'status': 'error',
                    'message': str(e)
                })
            print(f"  处理过程中发生错误: {str(e)}")
    
    print(f"图片处理完成，成功处理 {len([r for r in results if r['status'] == 'success'])}/{len(results)} 项")
    return results


def process_match_videos_new_method(excel_path, audios_dir, output_dir, api_key, language="zh"):
    """
    使用新方法为处理后的图片生成视频（避免文本错误）
    
    Args:
        excel_path (str): Excel文件路径
        audios_dir (str): 音频目录
        output_dir (str): 输出目录
        api_key (str): DashScope API密钥
        language (str): 生成语言，'zh'表示中文，'vi'表示越南语
        
    Returns:
        list: 视频生成结果列表
    """
    print(f"开始生成视频（新方法）: Excel={excel_path}, 音频目录={audios_dir}")
    
    # 处理图片
    image_results = process_match_images_new_method(excel_path, output_dir, api_key, language=language)
    
    # 根据match_id对成功的结果进行分组，确保每组只生成一个视频
    successful_results = [r for r in image_results if r['status'] == 'success']
    grouped_results = defaultdict(list)
    
    for result in successful_results:
        match_info = result['match_info']
        match_id = match_info.get('match_id', '')
        # 如果没有match_id，则使用图片路径作为分组依据
        if not match_id:
            match_id = result['image_path']
        grouped_results[match_id].append(result)
    
    print(f"根据match_id分组完成，共{len(grouped_results)}组需要生成视频")
    
    # 确保视频输出目录存在
    videos_dir = os.path.join(output_dir, 'videos')
    os.makedirs(videos_dir, exist_ok=True)
    print(f"创建/确认视频输出目录: {videos_dir}")
    
    video_results = []
    
    # 获取音频文件
    audio_files = []
    audios_path = Path(audios_dir)
    for ext in ['*.mp3', '*.wav', '*.aac', '*.flac', '*.m4a']:
        audio_files.extend(audios_path.glob(ext))
    
    print(f"在音频目录 {audios_dir} 中找到 {len(audio_files)} 个音频文件")
    
    if not audio_files:
        print("警告: 未找到音频文件，将跳过所有视频生成")
    
    # 为每个分组生成一个视频
    group_count = len(grouped_results)
    print(f"开始为 {group_count} 个分组生成视频")
    
    for i, (match_id, group_results) in enumerate(grouped_results.items()):
        try:
            # 使用组内第一个结果作为代表
            representative_result = group_results[0]
            match_info = representative_result['match_info']
            image_path = representative_result['image_path']
            
            print(f"正在生成第 {i+1}/{group_count} 个视频，分组ID: {match_id}")
            
            # 构造视频输出路径
            match_time = match_info['match_time'].replace(':', '-')
            team_a = match_info['team_a']
            team_b = match_info['team_b']
            
            # 清理文件名中的非法字符
            safe_match_time = sanitize_filename(match_time)
            safe_team_a = sanitize_filename(team_a)
            safe_team_b = sanitize_filename(team_b)
            
            timestamp = int(time.time())
            # 确保文件名包含球队信息
            if safe_team_a and safe_team_b:
                video_filename = f"{safe_match_time}_{safe_team_a}_vs_{safe_team_b}_{timestamp}.mp4"
            elif safe_team_a:
                video_filename = f"{safe_match_time}_{safe_team_a}_{timestamp}.mp4"
            elif safe_team_b:
                video_filename = f"{safe_match_time}_{safe_team_b}_{timestamp}.mp4"
            else:
                # 从图片文件名中提取名称
                image_name = Path(image_path).stem
                video_filename = f"{image_name}_{timestamp}.mp4"
            
            video_output_path = os.path.join(videos_dir, video_filename)
            print(f"  视频输出路径: {video_output_path}")
            
            # 生成视频描述（仅使用基本描述，避免额外的文本生成指令）
            prompt = f"""
                Animate the original football poster while keeping the original layout and all elements in place.
                Enhance scene details and realism with subtle motion, lighting, and environmental effects (e.g., waving grass, glowing lights, slight camera movement).
                Do not modify or replace any text content — you may only apply non-destructive effects like glow, shadow, or color adjustment.
                The team logo must remain visible and unchanged in position and design.
                Do not introduce any unrelated or new visual elements.
            """
            print(f"  视频生成提示词: {prompt}")
            
            if not audio_files:
                # 为组内所有比赛添加结果
                for result in group_results:
                    video_results.append({
                        'match_info': result['match_info'],
                        'status': 'failed',
                        'message': '未找到音频文件'
                    })
                print("  跳过（未找到音频文件）")
                continue
            
            # 随机选择一个音频文件
            selected_audio = random.choice(audio_files)
            print(f"  选择音频文件: {selected_audio.name}")
            
            # 生成视频
            success, logs = process_single_image_with_audio(
                image_path, 
                prompt, 
                "720P",  # 默认分辨率
                [str(selected_audio)], 
                video_output_path,
                "",  # 空的负面提示词
                duration=5.0   # 固定时长5秒
            )
            
            # 为组内所有比赛添加结果
            if success:
                for result in group_results:
                    video_results.append({
                        'match_info': result['match_info'],
                        'video_path': video_output_path,
                        'status': 'success',
                        'message': '视频生成成功'
                    })
                print(f"  视频生成成功: {video_output_path}")
            else:
                for result in group_results:
                    video_results.append({
                        'match_info': result['match_info'],
                        'video_path': video_output_path,
                        'status': 'failed',
                        'message': logs
                    })
                print(f"  视频生成失败: {logs}")
                
        except Exception as e:
            # 为组内所有比赛添加错误结果
            for result in group_results:
                video_results.append({
                    'match_info': result['match_info'],
                    'status': 'error',
                    'message': str(e)
                })
            print(f"  视频生成过程中发生错误: {str(e)}")
    
    # 处理图片处理失败的项目
    failed_results = [r for r in image_results if r['status'] != 'success']
    for result in failed_results:
        video_results.append({
            'match_info': result['match_info'],
            'status': 'skipped',
            'message': f"跳过视频生成：{result['message']}"
        })
        print(f"跳过视频生成: {result['message']}")
    
    successful_video_count = len([r for r in video_results if r['status'] == 'success'])
    print(f"视频生成完成，成功生成 {successful_video_count}/{len(video_results)} 个视频")
    return video_results


def process_match_videos(excel_path, audios_dir, output_dir, api_key, image_results=None, language="zh"):
    """
    为处理后的图片生成视频
    
    Args:
        excel_path (str): Excel文件路径
        audios_dir (str): 音频目录
        output_dir (str): 输出目录
        api_key (str): DashScope API密钥
        image_results (list): 可选的已处理图片结果，如果提供则不再重新处理图片
        
    Returns:
        list: 视频生成结果列表
    """
    print(f"开始生成视频: Excel={excel_path}, 音频目录={audios_dir}")
    
    # 如果没有提供已处理的图片结果，则处理图片
    if image_results is None:
        image_results = process_match_images(excel_path, output_dir, api_key, language=language)
    else:
        print("使用已提供的图片处理结果，跳过图片处理步骤")
    # return []
    # 确保视频输出目录存在
    videos_dir = os.path.join(output_dir, 'videos')
    os.makedirs(videos_dir, exist_ok=True)
    print(f"创建/确认视频输出目录: {videos_dir}")
    
    video_results = []
    
    # 获取音频文件
    audio_files = []
    audios_path = Path(audios_dir)
    for ext in ['*.mp3', '*.wav', '*.aac', '*.flac', '*.m4a']:
        audio_files.extend(audios_path.glob(ext))
    
    print(f"在音频目录 {audios_dir} 中找到 {len(audio_files)} 个音频文件")
    
    if not audio_files:
        print("警告: 未找到音频文件，将跳过所有视频生成")
    
    # 为每个成功处理的图片生成视频
    successful_image_count = len([r for r in image_results if r['status'] == 'success'])
    print(f"开始为 {successful_image_count} 个成功处理的图片生成视频")
    
    for i, result in enumerate(image_results):
        if result['status'] == 'success':
            try:
                match_info = result['match_info']
                image_path = result['image_path']
                
                print(f"正在生成第 {i+1}/{successful_image_count} 个视频")
                
                # 构造视频输出路径
                match_time = match_info['match_time'].replace(':', '-')
                team_a = match_info['team_a']
                team_b = match_info['team_b']
                
                # 清理文件名中的非法字符
                safe_match_time = sanitize_filename(match_time)
                safe_team_a = sanitize_filename(team_a)
                safe_team_b = sanitize_filename(team_b)
                
                timestamp = int(time.time())
                # 确保文件名包含球队信息
                if safe_team_a and safe_team_b:
                    video_filename = f"{safe_match_time}_{safe_team_a}_vs_{safe_team_b}_{timestamp}.mp4"
                elif safe_team_a:
                    video_filename = f"{safe_match_time}_{safe_team_a}_{timestamp}.mp4"
                elif safe_team_b:
                    video_filename = f"{safe_match_time}_{safe_team_b}_{timestamp}.mp4"
                else:
                    # 从图片文件名中提取名称
                    image_name = Path(image_path).stem
                    video_filename = f"{image_name}_{timestamp}.mp4"
                
                video_output_path = os.path.join(videos_dir, video_filename)
                print(f"  视频输出路径: {video_output_path}")
                
                # 生成视频描述（仅使用基本描述，避免额外的文本生成指令）
                prompt = f"比赛：{team_a} vs {team_b}，时间：{match_time}。要求：让图片动起来，可以扩展场景，丰富画面细节，但不能出现与原始图片无关的内容，保持原始图片的布局和元素不变。"
                print(f"  视频生成提示词: {prompt}")
                
                if not audio_files:
                    video_results.append({
                        'match_info': match_info,
                        'status': 'failed',
                        'message': '未找到音频文件'
                    })
                    print("  跳过（未找到音频文件）")
                    continue
                
                # 随机选择一个音频文件
                selected_audio = random.choice(audio_files)
                print(f"  选择音频文件: {selected_audio.name}")
                
                # 生成视频
                success, logs = process_single_image_with_audio(
                    image_path, 
                    prompt, 
                    "720P",  # 默认分辨率
                    [str(selected_audio)], 
                    video_output_path,
                    ""  # 空的负面提示词
                )
                
                if success:
                    video_results.append({
                        'match_info': match_info,
                        'video_path': video_output_path,
                        'status': 'success',
                        'message': '视频生成成功'
                    })
                    print(f"  视频生成成功: {video_output_path}")
                else:
                    video_results.append({
                        'match_info': match_info,
                        'video_path': video_output_path,
                        'status': 'failed',
                        'message': logs
                    })
                    print(f"  视频生成失败: {logs}")
                    
            except Exception as e:
                video_results.append({
                    'match_info': match_info,
                    'status': 'error',
                    'message': str(e)
                })
                print(f"  视频生成过程中发生错误: {str(e)}")
        else:
            # 图片处理失败的项目
            video_results.append({
                'match_info': result['match_info'],
                'status': 'skipped',
                'message': f"跳过视频生成：{result['message']}"
            })
            print(f"跳过第 {i+1} 项视频生成: {result['message']}")
    
    successful_video_count = len([r for r in video_results if r['status'] == 'success'])
    print(f"视频生成完成，成功生成 {successful_video_count}/{len(video_results)} 个视频")
    return video_results


def process_match_images(excel_path, output_dir, api_key, language="zh"):
    """
    处理Excel中的比赛信息，为每场比赛生成海报图片
    
    Args:
        excel_path (str): Excel文件路径
        output_dir (str): 输出目录
        api_key (str): DashScope API密钥
        language (str): 生成语言，'zh'表示中文，'vi'表示越南语
        
    Returns:
        list: 处理结果列表
    """
    print(f"开始处理图片: Excel={excel_path}")
    
    # 读取Excel数据
    matches_data = read_excel_data(excel_path)
    if not matches_data:
        return []
    
    # 确保输出目录存在
    images_output_dir = os.path.join(output_dir, 'images')
    os.makedirs(images_output_dir, exist_ok=True)
    print(f"创建/确认图片输出目录: {images_output_dir}")
    
    results = []
    
    # 处理每场比赛
    for i, match_info in enumerate(matches_data):
        try:
            print(f"正在处理第 {i+1}/{len(matches_data)} 项: {match_info['team_a']} vs {match_info['team_b']}")
            
            # 生成文件名
            safe_team_a = re.sub(r'[<>:"/\\|?*]', '_', match_info['team_a'])
            safe_team_b = re.sub(r'[<>:"/\\|?*]', '_', match_info['team_b'])
            
            # 根据语言添加语言标识
            lang_suffix = "_vi" if language == "vi" else ""
            filename = f"{safe_team_a}_vs_{safe_team_b}{lang_suffix}_{uuid.uuid4().hex[:8]}.png"
            output_path = os.path.join(images_output_dir, filename)
            
            # 构造海报生成参数（使用越南语）
            title = f"{match_info['team_a']} vs {match_info['team_b']}"
            sub_title = match_info['match_time']
            body_text = match_info['copywriting']

            
            # 使用越南语风格构造提示词，充分利用Excel中的赛事信息
            prompt_text_zh = f"""
生成一张足球海报，{match_info['team_a']} VS {match_info['team_b']}，
背景要用足球场的鸟瞰图，
主要语言是越南语，
除了两个队伍的图标外， 不要出现其他图标。
信息要全部使用越南语，注意越南语不要出现文本错误。
比赛时间：{sub_title}，
还要有文案： {body_text}
文案要做得显眼一点。
"""
            
            # 生成海报
            success, result = generate_poster(
                api_key=api_key,
                title=title,
                sub_title=sub_title,
                body_text=body_text,
                prompt_text_zh=prompt_text_zh,
                wh_ratios="竖版",
                output_path=output_path,
                language=language
            )
            
            if success:
                results.append({
                    'match_info': match_info,
                    'image_path': output_path,
                    'status': 'success',
                    'message': '海报生成成功'
                })
                print(f"  海报生成成功: {output_path}")
            else:
                results.append({
                    'match_info': match_info,
                    'image_path': None,
                    'status': 'failed',
                    'message': result
                })
                print(f"  海报生成失败: {result}")
                
        except Exception as e:
            results.append({
                'match_info': match_info,
                'status': 'error',
                'message': str(e)
            })
            print(f"  处理过程中发生错误: {str(e)}")
    
    print(f"图片处理完成，成功处理 {len([r for r in results if r['status'] == 'success'])}/{len(results)} 项")
    return results
